package com.ziytek.web.citizen.util;

import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @className ZipReadUtil
 * @description: ZIP文件读取工具类
 * @jdkVersion: 1.8
 * @author: fhx
 * @date: 2024/7/2 9:53
 */

@Slf4j
public class ZipUtil {

    public static void xlsxCreateAndSave(Workbook workbook, String key, String beginTimeStr) {
        // 将工作簿写入文件
        FileOutputStream outputStream = null;
        try {

            String[] keyArr = key.split(ServerConstant.DATA_SEPARATOR);
            if (keyArr.length != NumConstant.INT_THREE) {
                return;
            }

            int tier = NumberUtils.toInt(keyArr[NumConstant.INT_ONE]);
            String filename = NumberUtils.toInt(keyArr[NumConstant.INT_ZERO])
                    + ServerConstant.DATA_SEPARATOR_LIND +
                    (tier <= NumConstant.INT_EIGHT ? NumConstant.INT_ONE : NumConstant.INT_TWO)
                    + ServerConstant.DATA_SEPARATOR_LIND +
                    (tier <= NumConstant.INT_EIGHT ? tier : tier - NumConstant.INT_EIGHT)
                    + ServerConstant.DATA_SEPARATOR_LIND + NumberUtils.toInt(keyArr[NumConstant.INT_TWO])
                    + "(" + beginTimeStr + ")";

            filename = filename.replace(":", "_");
            outputStream = new FileOutputStream(LocationUtils.downloadLocationPath(keyArr[NumConstant.INT_ZERO], beginTimeStr) + "/" + filename + ".xlsx");
            workbook.write(outputStream);
        } catch (IOException e) {
            log.error("XLSX file generation failed: {}", e.getMessage());
        } finally {
            // 关闭输出流
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                log.error("XLSX file close failed: {}", e.getMessage());
            }
        }
    }

    public static void zipDirectoryAsync(String sourceDir, String zipFile) {
        try {
            zipDirectory(sourceDir, zipFile);
            log.info("Zip Directory successfully zipped to {}", zipFile);
        } catch (Exception e) {
            log.error("Error while zipping directory: {}", e.getMessage());
        }
    }

    public static void zipDirectory(String sourceDir, String zipFile) throws IOException {
        FileOutputStream fos = new FileOutputStream(zipFile);
        ZipOutputStream zos = new ZipOutputStream(fos);
        File dir = new File(sourceDir);

        addDirectoryToZip(dir, dir.getName(), zos);

        zos.close();
        fos.close();
    }


    private static void addDirectoryToZip(File dir, String baseName, ZipOutputStream zos) {
        File[] files = dir.listFiles();
        int filesCount;
        if (files == null || files.length == 0) {
            log.error("files is null or empty");
            return;
        }
        filesCount = files.length;

        log.info("addDirectoryToZip filesCount:{}", filesCount);

        for (File file : files) {
            if (file.isDirectory()) {
                addDirectoryToZip(file, baseName + "/" + file.getName(), zos);
            } else {
                addFileToZip(file, baseName + "/" + file.getName(), zos);
            }
        }
    }

    private static void addFileToZip(File file, String entryName, ZipOutputStream zos) {
        FileInputStream fis = null;
        ZipEntry zipEntry = null;
        try {
            fis = new FileInputStream(file);
            zipEntry = new ZipEntry(entryName);
            zos.putNextEntry(zipEntry);

            byte[] bytes = new byte[1024];
            int length;
            while ((length = fis.read(bytes)) >= 0) {
                zos.write(bytes, 0, length);
            }

            fis.close();
            zos.closeEntry();
        } catch (Exception e) {
            log.error("addFileToZip error:{}", e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }

                if (zipEntry != null) {
                    zos.closeEntry();
                }
            } catch (IOException e) {
                log.error("addFileToZip close error:{}", e.getMessage());
            }
        }
    }

    public static boolean zipFileExistsAndSizeNotEmpty(String zipFilePath, long thresholdSize) {
        File zipFile = new File(zipFilePath);
        if (zipFile.exists() && zipFile.isFile()) {
            long fileSize = zipFile.length();
            log.info("ZIP file size:{} bytes", fileSize);

            // 判断文件大小是否超过某个阈值  // 1 MB = 1024 * 1024 bytes
            long thresholdSizeMix = 1024;
            thresholdSize = Math.max(thresholdSize, thresholdSizeMix);
            if (fileSize < thresholdSize) {
                log.error("ZIP file size is within the threshold of {} bytes", thresholdSize);
                return false;
            }
            return true;
        } else {
            log.error("The specified file does not exist or is not a regular file.");
            return false;
        }
    }


    public static boolean deleteDirectorySync(String directoryPath) {
        File directory = new File(directoryPath);
        if (directory.exists() && directory.isDirectory()) {
            boolean success = deleteDirectory(directory);
            if (success) {
                log.info("Directory successfully deleted.");
            } else {
                log.error("Failed to delete directory.");
                return false;
            }
        } else {
            log.error("The specified directory does not exist or is not a directory.");
        }

        return true;
    }

    public static boolean deleteDirectory(File directory) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        return directory.delete();
    }
}
